package com.beyond.flow.collect

import androidx.lifecycle.Lifecycle.State
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.beyond.flow.container.StateTuple1
import com.beyond.flow.container.StateTuple2
import com.beyond.flow.container.StateTuple3
import com.beyond.flow.inter.UiEvent
import com.beyond.flow.inter.UiState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlin.reflect.KProperty1

/**
 * @author chenshiyang
 * @time 2022/11/11 09:28
 * @name beyond-kotlin-frame
 * @class describe
 */
/**
 * state 的订阅 通过扩展反射消除模板代码
 */

class StateCollector<T : UiState>(
    private val flow: Flow<T>,
    private val lifecycleOwner: LifecycleOwner,
    private val state: State,
) {

    fun <A> collectPartial(
        prop1: KProperty1<T, A>,
        action: (A) -> Unit
    ) {
        flow.collectPartial(lifecycleOwner, prop1, state, action)
    }

    fun <A, B> collectPartial(
        prop1: KProperty1<T, A>,
        prop2: KProperty1<T, B>,
        action: (A, B) -> Unit
    ) {
        flow.collectPartial(lifecycleOwner, prop1, prop2, state, action)
    }

    fun <A, B, C> collectPartial(
        prop1: KProperty1<T, A>,
        prop2: KProperty1<T, B>,
        prop3: KProperty1<T, C>,
        action: (A, B, C) -> Unit
    ) {
        flow.collectPartial(lifecycleOwner, prop1, prop2, prop3, state, action)
    }

}

internal fun <T : UiState, A> Flow<T>.collectPartial(
    lifecycleOwner: LifecycleOwner,
    prop1: KProperty1<T, A>,
    state: State,
    action: (A) -> Unit
) {
    lifecycleOwner.lifecycleScope.launch {
        lifecycleOwner.repeatOnLifecycle(state) {
            this@collectPartial
                .map { StateTuple1(prop1.get(it)) }
                .distinctUntilChanged()
                .collect { (partialStateA) ->
                    action(partialStateA)
                }
        }
    }
}

internal fun <T : UiState, A, B> Flow<T>.collectPartial(
    lifecycleOwner: LifecycleOwner,
    prop1: KProperty1<T, A>,
    prop2: KProperty1<T, B>,
    state: State = State.STARTED,
    action: (A, B) -> Unit
) {
    lifecycleOwner.lifecycleScope.launch {
        lifecycleOwner.repeatOnLifecycle(state) {
            this@collectPartial
                .map { StateTuple2(prop1.get(it), prop2.get(it)) }
                .distinctUntilChanged()
                .collect { (partialStateA, partialStateB) ->
                    action(partialStateA, partialStateB)
                }
        }
    }
}

internal fun <T : UiState, A, B, C> Flow<T>.collectPartial(
    lifecycleOwner: LifecycleOwner,
    prop1: KProperty1<T, A>,
    prop2: KProperty1<T, B>,
    prop3: KProperty1<T, C>,
    state: State = State.STARTED,
    action: (A, B, C) -> Unit
) {
    lifecycleOwner.lifecycleScope.launch {
        lifecycleOwner.repeatOnLifecycle(state) {
            this@collectPartial
                .map { StateTuple3(prop1.get(it), prop2.get(it), prop3.get(it)) }
                .distinctUntilChanged()
                .collect { (partialStateA, partialStateB, partialStateC) ->
                    action(partialStateA, partialStateB, partialStateC)
                }
        }
    }
}


/**
 * 扩展 获取flow state 监听
 */
fun <S : UiState> Flow<S>.collectState(
    lifecycleOwner: LifecycleOwner,
    state: State = State.STARTED,
    action: StateCollector<S>.() -> Unit
) {
    // 传递给State收集器，用于开启多个collectPartial()方法
    StateCollector(this@collectState, lifecycleOwner, state).action()
}

/**
 * 事件流的订阅 消除模板代码
 */
fun <E : UiEvent> Flow<E>.collectEvent(
    lifecycleOwner: LifecycleOwner,
    state: State = State.STARTED,
    action: (E) -> Unit
) {
    lifecycleOwner.lifecycleScope.launch {
        lifecycleOwner.repeatOnLifecycle(state) {
            this@collectEvent.collect {
                action(it)
            }
        }
    }
}

